--[[
    雪月框架 - 矩形区域
    ---@author:雪月灬雪歌  2022-03-17 04:15:20

    非必要情况不要引用rect的handle值，而是使用一个公共rect
    一旦引用会生成一个jass的rect实例来返回正确handle值

]]
local cj = cj
local Rect = cj.Rect
local GetHandleId = cj.GetHandleId
local RemoveRect = cj.RemoveRect
local SetRect = cj.SetRect
local MoveRectTo = cj.MoveRectTo
local points = { 'LT', 'LB', 'C', 'RT', 'RB' }
---@class mRect
local mRect = {
    type = 'module',
    module = 'rect',
}
---@class cRect
local cRect = {
    type = 'class',
    class = 'rect',

    coord = {
        LT = { 0, 0 },
        LB = { 0, 0 },
        RT = { 0, 0 },
        RB = { 0, 0 },
    }, --坐标

    handle = nil,
}
--cRect.__index = cRect

local mt = {
    __index = function (self, key)
        if key == 'handle' or key == 'hid' then
            local minX = self.coord.LT[1]
            local maxX = self.coord.RT[1]

            local minY = self.coord.LB[2]
            local maxY = self.coord.LT[2]
            local h = Rect( minX, minY, maxX, maxY  )
            self.handle = h
            self.hid = GetHandleId(h)
            self.hasHandle = true
            return self[key]
        end
        return cRect[key]
    end
}

--- 销毁矩形区域
function cRect:del()
    setmetatable( self, nil )
    if self.hasHandle then
        RemoveRect( self.handle )
    end
    self.handle = nil
    self.hid = 0
end

local function template()
    ---@class rect : cRect
    local rct = {
        type = 'rect',
        coord = {},
        hid = 0,
    }
    setmetatable( rct, mt )
    return rct
end

---@ 新建矩形区域 魔兽标准 左下 右上 模式
function mRect:rect( LB_X, LB_Y,  RT_X, RT_Y )
    local rct = template()

    rct.coord.LT = { LB_X, RT_Y }       rct.coord.RT = { RT_X, RT_Y }

    rct.coord.LB = { LB_X, LB_Y }       rct.coord.RB = { RT_X, LB_Y }
    rct:init()
    return rct
end

---@ 坐标是否在区域内
function cRect:isCoordInRect( x, y )
    local minX = self.coord.LT[1]
    local maxX = self.coord.RT[1]

    local minY = self.coord.LB[2]
    local maxY = self.coord.LT[2]
    return
        ( x >= minX and x <= maxX ) and
        ( y >= minY and y <= maxY )
end

--- 根据坐标点 宽度 高度 新建矩形区域
--- proXY： xy轴相对于宽高的偏移比例 将xy看做是坐标系的原点。 全0则在第一象限 全1则在第三象限
---@param x real 依据坐标x
---@param y real 依据坐标y
---@param width real 宽度
---@param height real 高度
---@param proX real 0.0~1.0 [可空]默认0.5则在中心点 x 在宽度上的比例
---@param proY real 0.0~1.0 [可空]默认0.5则在中心点 y 在高度上的比例
function mRect:rectFormCoord( x, y, width, height, proX, proY )
    local rct = template()
    if not proX then proX = 0.5 end
    if not proY then proY = 0.5 end

    local LB_X = x - width * (proX)   --minX
    local LB_Y = y - height * (proY)

    local RT_X = x + width * (1-proX)   --maxX
    local RT_Y = y + height * (1-proY)

    rct.coord.LT = { LB_X, RT_Y }       rct.coord.RT = { RT_X, RT_Y }


    rct.coord.LB = { LB_X, LB_Y }       rct.coord.RB = { RT_X, LB_Y }
    rct:init()
    return rct
end

---@private 初始化
function cRect:init()
    local minX = self.coord.LT[1]
    local maxX = self.coord.RT[1]

    local minY = self.coord.LB[2]
    local maxY = self.coord.LT[2]
    self.coord.C = {
        minX + (maxX - minX) * 0.5 ,
        minY + (maxY - minY) * 0.5
    }
    self.hasHandle = false
end

--- 新建矩形区域 以左上角点为起点
---@param params table x|y|width|height
---@return rect
function mRect:new( params )
    params = params or {}
    local x, y, width, height =
    params.x or 0,
    params.y or 0,
    params.width or 0,
    params.height or 0

    return self:rectFormCoord( x, y, width, height, 0, 0 )
end

--- 获取区域内的随机点
---@return real x
---@return real y
function cRect:getRandom()
    local minX = self.coord.LT[1]
    local maxX = self.coord.RT[1]

    local minY = self.coord.LB[2]
    local maxY = self.coord.LT[2]
    return
        math.randomReal( minX, maxX ),
        math.randomReal( minY, maxY)
end

--- 获取区域中心点
---@return real x
---@return real y
function cRect:getCenter()
    local center = self.coord.C
    return center[1], center[2]
end

--- 获取区域点
---@param point string LT|LB|C|RT|RB| 分别对应 左上 左下 中心 右上 右下
---@return real|nil x
---@return real|nil y
function cRect:getPoint( point )
    local p = self.coord[point] or {}
    return p[1] , p[2]
end


--- 移动区域 一段距离
---@param distanceX real x轴移动的距离
---@param distanceY real y轴移动的距离
function cRect:moveByDistance( distanceX, distanceY )
    distanceX = distanceX or 0
    distanceY = distanceY or 0
    local coord = self.coord
    local x = coord.C[1] + distanceX
    local y = coord.C[2] + distanceY

    --coord.C[1] = x
    --coord.C[2] = y

    for _, point in ipairs(points) do
        coord[point][1] = coord[point][1] + distanceX
        coord[point][2] = coord[point][2] + distanceY
    end

    if self.hasHandle then
        MoveRectTo(self.handle, x, y)
    end
end

--- 移动区域 根据 中心点
---@param newX real 目标点x
---@param newY real 目标点y
function cRect:moveByCenter( newX, newY )
    local coord = self.coord
    local distanceX = newX - coord.C[1]
    local distanceY = newY - coord.C[2]
    self:moveByDistance( distanceX, distanceY )
end

--- 调整区域大小
---@param width real 宽度 可选
---@param height real 高度 可选
function cRect:resize( width, height )
    local coord = self.coord
    local minX = coord.LT[1]
    local maxX = coord.RT[1]
    if width then
        local w = width - (maxX - minX) --需要增加或减少的宽度差值
        w = w * 0.5
        minX = minX - w
        maxX = maxX + w
    end

    local minY = coord.LB[2]
    local maxY = coord.LT[2]
    if height then
        local h = height - (maxY - minY)
        h = h * 0.5
        minY = minY - h
        maxY = maxY + h
    end

    coord.LT = { minX, maxY }       coord.RT = { maxX, maxY }

    coord.LB = { minX, minY }       coord.RB = { maxX, minY }

    coord.C = {
        minX + (maxX - minX) * 0.5 ,
        minY + (maxY - minY) * 0.5
    }
    if self.hasHandle then
        SetRect(self.handle, minX, minY, maxX, maxY )
    end
end

--- 复制区域的坐标 大小 无关其他
---@param orig rect 模板
function cRect:copy( orig )
    local coord = self.coord
    local orig_coord = orig.coord

    for _, point in ipairs(points) do
        coord[point][1] = orig_coord[point][1]
        coord[point][2] = orig_coord[point][2]
    end
    if self.hasHandle then
        SetRect(self.handle,
            coord.LB[1], --minX
            coord.LB[2], --minY
            coord.RT[1], --maxX
            coord.RT[2]  --maxY
        )
    end
end

--- 和copy一样,只不过这个是作为模板来复制给其他rect
---@param targetRect rect 复制到目标rect
function cRect:copyTo( targetRect )
    local coord_target = targetRect.coord
    local coord_source = self.coord

    for _, point in ipairs(points) do
        coord_target[point][1] = coord_source[point][1]
        coord_target[point][2] = coord_source[point][2]
    end

    if targetRect.hasHandle then
        SetRect(targetRect.handle,
            coord_target.LB[1], --minX
            coord_target.LB[2], --minY
            coord_target.RT[1], --maxX
            coord_target.RT[2]  --maxY
        )
    end
end

--- 调整区域宽度
---@param w real 宽度
function cRect:setWidth( w )
    self:resize( w )
end

--- 调整区域高度
---@param h real 高度
function cRect:setHeight( h )
    self:resize( nil, h )
end

--- 获取区域高度
---@return real
function cRect:getWidth()
    local coord = self.coord
    return coord.RT[1] - coord.LT[1]
end

--- 获取区域高度
---@return real
function cRect:getHeight()
    local coord = self.coord
    return coord.LT[2] - coord.LB[2]
end

return mRect
